#include <stdio.h>
#include<math.h>
#include <stdint.h>
#include "aim.h"
#include <stdlib.h>


typedef uint32_t uint_t;
typedef unsigned char byte_t;
static const uint_t uint_t_BITS_SIZE = 32;

// values of (sin(y * M_PI*2 / 64) * 16 + 16); for y in [0, 64)
static const uint_t sinTable [] = { 15, 17, 19, 20, 22, 23, 24, 26,
                                  27, 28, 29, 30, 30, 31, 31, 31,
                                  32, 31, 31, 31, 30, 30, 29, 28,
                                  27, 26, 24, 23, 22, 20, 19, 17,
                                  16, 14, 12, 11,  9,  8,  7,  5,
                                   4,  3,  2,  1,  1,  0,  0,  0,
                                   0,  0,  0,  0,  1,  1,  2,  3,
                                   4,  5,  7,  8,  9, 11, 12, 14};


static inline uint_t reverseSubBytes2(uint_t t){
    uint_t result = (t & 0xFF);
    result = (result << 8) | ((t & 0xFF00) >> 8);
    result = (result << 8) | ((t & 0xFF0000) >> 16);
    result = (result << 8) | ((t & 0xFF000000) >> 24);
    return result;
}


static inline uint_t getMovement(uint_t y){
    //equal results for y < 10000000
    uint_t r = y % 64;
    if ( r == 0 ){
        return (uint_t) (sin(y * M_PI*2 / 64) * 16 + 16);
    }else if (r == 32){
         return (uint_t) (sin(y * M_PI*2 / 64) * 16 + 16);
    }else{
        return sinTable[r];
    }
}



void
exercise(struct image * restrict in, struct image * restrict out){
	/* Do your image transformation here. Delete the code below
	 * first, especially when testing with large images! Modify
	 * the image, not just the printing code. */

    uint_t * pin =(uint_t *) in->bitmap;
    uint_t * pout = (uint_t *) out->bitmap;

    const uint_t startTable [] = {0, ~0};

    uint_t innerLoopSteps = in->cols / uint_t_BITS_SIZE;

    for (uint_t y = 0; y < in->rows; y++) {

        uint_t movement = getMovement(y);

	if ( movement == 0 ){
		 for(uint_t * end = pin + innerLoopSteps; pin != end; ++pin, ++pout){
		 	*pout = *pin;
		 }
	}else if (movement == 32 ){
 		 bool p = ((*pin) >> 7) & 1;
		 uint_t previous = startTable[p];
		 for(uint_t * end = pin + innerLoopSteps; pin != end; ++pin, ++pout){
 		       *pout = previous;
        	       previous = *pin;
		 }
	}else{
		bool p = ((*pin) >> 7) & 1;
		uint_t previous = startTable[p];
		uint_t current;
		uint_t leftShift = uint_t_BITS_SIZE - movement;
 	        for(uint_t * end = pin + innerLoopSteps; pin != end; ++pin, ++pout){
        	    current = reverseSubBytes2(*pin);
	            *pout =  reverseSubBytes2( (previous << leftShift) | (current >> movement) );
	            previous = current;
		}
	}
    }
}



